/*
Source Code for the cube mover  executable
 */





//#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

struct player {
	float xPos;
	float yPos;
	float zPos;
	float size;
};

// GLOBAL VARIABLES ////////////////////////////////////////////////////////////

//global variables to keep track of window width and height.
//set to initial values for convenience, but we need variables
//for later on in case the window gets resized.
int windowWidth = 512, windowHeight = 512;

float cameraTheta, cameraPhi, cameraRadius; //camera position in spherical coordinates
float cameraX, cameraY, cameraZ;            //camera position in cartesian coordinates
struct player myPlayer;


// our current object type

// END GLOBAL VARIABLES ///////////////////////////////////////////////////////

//
// void computeArcballPosition(float theta, float phi, float radius,
//                              float &x, float &y, float &z);
//
// This function updates the camera's position in cartesian coordinates based 
//  on its position in spherical coordinates. The user passes in the current phi,
//  theta, and radius, as well as variables to hold the resulting X, Y, and Z values.
//  Those variables for X, Y, and Z values get filled with the camera's position in R3.
//
void computeArcballPosition(float theta, float phi, float radius,
                            float &x, float &y, float &z) {
    x = radius * sinf(theta)*sinf(phi);
    y = radius * -cosf(phi);
    z = radius * -cosf(theta)*sinf(phi);
}

//  void drawGrid()
//
//      Simple function to draw a grid in the X-Z plane using GL_LINES.
//
void drawGrid() {
    glDisable(GL_LIGHTING);

    glColor3f(1,1,1);
    glBegin(GL_LINES); {
        //draw the lines along the Z axis
        for(int i = 0; i < 11; i++) {
            glVertex3f((i-5), 0, -5);
            glVertex3f((i-5), 0, 5);
        }
        //draw the lines along the X axis
        for(int i = 0; i < 11; i++) {
            glVertex3f(-5, 0, (i-5));
            glVertex3f(5, 0, (i-5));
        }
    }; glEnd();

    glEnable(GL_LIGHTING);
}

// void drawWall(int w, int h)
// this draws a wall

void drawWall()
{  
  glBegin(GL_QUADS);
  {
    glVertex3f(-5.0,0.0,5.0);
    glVertex3f(5.0,0.0,5.0);
    glVertex3f(5.0,0.0,-5.0);
    glVertex3f(-5.0,0.0,-5.0);

  
  }; glEnd();
}


//
//  void resizeWindow(int w, int h)
//
//      We will register this function as GLUT's reshape callback.
//   When the window is resized, the OS will tell GLUT and GLUT will tell
//   us by calling this function - GLUT will give us the new window width
//   and height as 'w' and 'h,' respectively - so save those to our global vars.
//
void resizeWindow(int w, int h) {
    float aspectRatio = w / (float)h;

    windowWidth = w;
    windowHeight = h;

    //update the viewport to fill the window
    glViewport(0, 0, w, h);

    //update the projection matrix with the new window properties
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0,aspectRatio,0.1,100000);
}


//
//  void initScene()
//
//  A basic scene initialization function; should be called once after the
//      OpenGL context has been created. Doesn't need to be called further.
//      Just sets up a few function calls so that our main() is cleaner.
//
void initScene() {
    glEnable(GL_DEPTH_TEST);

    //this is some code to enable a default light for the scene;
    //feel free to play around with this, but we won't talk about
    //lighting in OpenGL for another couple of weeks yet.
    float lightCol[4] = { 1, 1, 1, 1};
    float ambientCol[4] = {0.0, 0.0, 0.0, 1.0};
    float lPosition[4] = { 10, 10, 10, 1 };
    glLightfv(GL_LIGHT0,GL_POSITION,lPosition);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,lightCol);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientCol);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    //tell OpenGL not to use the material system; just use whatever we pass with glColor()
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

    //tells OpenGL to blend colors across triangles. Once lighting is
    //enabled, this means that objects will appear smoother - if your object
    //is rounded or has a smooth surface, this is probably a good idea;
    //if your object has a blocky surface, you probably want to disable this.
    glShadeModel(GL_SMOOTH);
}

//
//  void renderScene()
//
//  GLUT callback for scene rendering. Sets up the modelview matrix, renders
//      a teapot to the back buffer, and switches the back buffer with the
//      front buffer (what the user sees).
//
void renderScene(void) {
    //update the modelview matrix based on the camera's position
    glMatrixMode(GL_MODELVIEW);             //make sure we aren't changing the projection matrix!
    glLoadIdentity();

    gluLookAt(cameraX, cameraY, cameraZ,     //camera is located at (x,y,z)
                myPlayer.xPos, myPlayer.yPos, myPlayer.zPos,            //camera is looking at (0,0,0)
                0.0f, 1.0f, 0.0f);           //up vector is (0,1,0) (positive Y)

    //clear the render buffer
    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix(); {
        glColor3f(1.0,0.0,0.1);
        glTranslatef(myPlayer.xPos, myPlayer.yPos, myPlayer.zPos);
	// draw our cube as solid 
	glutSolidCube( myPlayer.size );
    }; glPopMatrix();

    //move the grid down a touch so that it doesn't overlap with the axes
    glPushMatrix();
       glColor3f(0.6,0.6,0.6);
       glTranslatef(0,-0.5,0);
        drawWall();
    glPopMatrix();

    glPushMatrix();
      glColor3f(0.8,0.8,0.8);
      glTranslatef(-5,0,0);
      glTranslatef(0,5.0,0);
      glRotatef(90,0,0,1);
      drawWall();
    glPopMatrix();
    
//    glPushMatrix();
//      glRotate(0,0,1);
 //     glTranslate(-5,0,0);
  //    drawWall();
   // glPopMatrix();    

//    glPushMatrix();
 //     glRotate(0,0,1);
  //    glTranslate(-5,0,0);
   //   drawWall();
   // glPopMatrix();    



    //push the back buffer to the screen
    glutSwapBuffers();
}


//
//  void normalKeys(unsigned char key, int x, int y)
//
//      GLUT keyboard callback for regular characters.
//
void normalKeys(unsigned char key, int x, int y) {
    //kindly quit if the user requests!
    if(key == 'q' || key == 'Q')
        exit(0);

	switch( key ) {
		case 'd':
		case 'D':
			if(myPlayer.xPos < 4.5)
			  myPlayer.xPos += 0.1f;
			break;
			
		case 'a':
		case 'A':
			if(myPlayer.xPos > -4.5)
			  myPlayer.xPos -= 0.1f;
			break;
			
		case 'w':
		case 'W':
			if(myPlayer.zPos > -4.5)
			  myPlayer.zPos -= 0.1f;
			break;

		case 's':
		case 'S':
			if(myPlayer.zPos < 4.5)
			  myPlayer.zPos += 0.1f;
			break;
		case 'r':
		case 'R':
			if(myPlayer.yPos < 9.5)
			  myPlayer.yPos += 0.1f;
			break;
		case 'f':
		case 'F':
			if(myPlayer.yPos > 0)
			  myPlayer.yPos -= 0.1f;
			break;
	}
}

//
// void myTimer(int value)
//
//  We have to take an integer as input per GLUT's timer function prototype;
//  but we don't use that value so just ignore it. We'll register this function
//  once at the start of the program, and then every time it gets called it
//  will perpetually re-register itself and tell GLUT that the screen needs
//  be redrawn. yes, I said "needs be."
//
void myTimer(int value) {
    glutPostRedisplay();
    glutTimerFunc((unsigned int)(1000.0 / 60.0), myTimer, 0);
}



//
//  int main(int argc, char **argv)
//
//      No offense but you should probably know what the main function does.
//      argc is the number of arguments to the program (program name included),
//      and argv is an array of strings; argv[i] is the ith command line
//      argument, where 0 <= i <= argc
//
int main(int argc, char **argv) {
    //create a double-buffered GLUT window at (50,50) with predefined windowsize
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50,50);
    glutInitWindowSize(windowWidth,windowHeight);
    glutCreateWindow("Something");

    //give the camera a 'pretty' starting point!
    cameraRadius = 12.0f;
    cameraTheta = 2.80;
    cameraPhi = 2.0;

    myPlayer.xPos = 0.0f;
    myPlayer.yPos = 0.0f;
    myPlayer.zPos = 0.0f;
    myPlayer.size = 1.0f;
 	
    computeArcballPosition(cameraTheta, cameraPhi, cameraRadius,
						   cameraX, cameraY, cameraZ);
	

    //register callback functions...
    glutKeyboardFunc(normalKeys);
    glutDisplayFunc(renderScene);
    glutReshapeFunc(resizeWindow);

    //do some basic OpenGL setup
    initScene();
    glutTimerFunc((unsigned int)(1000.0 / 60.0), myTimer, 0);

    //and enter the GLUT loop, never to exit.
    glutMainLoop();

    return(0);
}
